/*
 * addon_system.cpp
 *
 *  Created on: 2010-1-7
 *      Author: gavinkwoe
 */

#include "addon_features.h"

#if (__ADDON_TARGET__ == __TARGET_SYMBIAN)

#include "addon_std.h"
#include "addon_mem.h"
#include "addon_objbase.h"
#include "addon_regex.h"

//#include <e32cmn.h>

/*************************************************************************
* GUID
*************************************************************************/

ADDON_DEFINED_GUID( IAddonSRegex, 1, "50DDAAC3-29EF-4762-876A-67788C373A0E" )

/*************************************************************************
* STRUCTURE
*************************************************************************/

struct __struct_addon_SRegex_data;
typedef struct __struct_addon_SRegex_data		addon_SRegex_data_t;
typedef struct __struct_addon_SRegex_data *		addon_SRegex_data_ptr_t;

/*************************************************************************
* DEFINITION
*************************************************************************/

struct __struct_addon_SRegex_data
{
	unsigned long		ref_cnt;		// reference count
	unsigned long		ncond;
	addon_regcond_ptr_t	pcond;
};

/*************************************************************************
* LOCAL FUNCTIONS
*************************************************************************/

unsigned long	__CSRegex_Construct( ADDON_REF(IObject) thiz, void * usr_data );
unsigned long	__CSRegex_Destruct( ADDON_REF(IObject) thiz );
unsigned long	__CSRegex_AddRef( ADDON_REF(IObject) thiz );
unsigned long	__CSRegex_Release( ADDON_REF(IObject) thiz );

unsigned long	__CSRegex_SetPattern( ADDON_REF(IObject) thiz, addon_regcond_ptr_t pcond, unsigned long ncond );
unsigned long	__CSRegex_Match( ADDON_REF(IObject) thiz, unsigned short * str, unsigned long len,
														unsigned long nmatch, addon_regmatch_ptr_t pmatch );

unsigned long	__wstrchr( unsigned short * str, unsigned long len, unsigned short chr );
unsigned long	__match_condition( unsigned short * str, unsigned long len,
							addon_regcond_ptr_t pcond, addon_regmatch_ptr_t pmatch );

// const void * const __coclass_vtbl[] =
// {
// 	// IObject
// 	(void *)__CSRegex_Construct,
// 		(void *)__CSRegex_Destruct,
// 		(void *)__CSRegex_AddRef,
// 		(void *)__CSRegex_Release,
// 		
// 		// IAddonSetting
// 		(void *)__CSRegex_SetPattern,
// 		(void *)__CSRegex_Match
// };
// 
// const addon_coclass_desc_t __coclass_desc =
// {
// 	(unsigned char *)__coclass_vtbl,
// 		(unsigned long)sizeof( addon_SRegex_data_t )
// };

/*************************************************************************
* IMPLEMENTATION
*************************************************************************/

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __wstrchr( unsigned short * str, unsigned long len, unsigned short chr )
{
	register unsigned long i;
	
	for ( i = 0; i < len; ++i )
	{
		if ( chr == str[i] )
		{
			return i;
		}
	}

	return len + 1;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __match_condition( unsigned short * str, unsigned long len,
						addon_regcond_ptr_t pcond, addon_regmatch_ptr_t pmatch )
{
	register unsigned long	i;
	unsigned long			off;
	unsigned long			hit;
	
	for ( hit = 0, i = 0; hit < pcond->max_match && i < len; ++hit, ++i )
	{
		off = __wstrchr( pcond->char_set, pcond->char_cnt, str[i] );
		if ( off >= pcond->char_cnt )
			break;
	}
	
	if ( hit >= pcond->min_match && hit <= pcond->max_match )
	{
		pmatch->offset_beg = 0;
		pmatch->offset_end = i;
		return 1;
	}

	return 0;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CSRegex_Construct( ADDON_REF(IObject) thiz, void * usr_data )
{
	addon_SRegex_data_ptr_t obj_data = (addon_SRegex_data_ptr_t)ADDON_GET_DATA( thiz );

	ADDON_UNUSED( usr_data );
	
	if ( NULL == obj_data )
		return ADDON_FAILED;

	obj_data->ref_cnt	= 1;
	obj_data->ncond		= 0;
	obj_data->pcond		= NULL;
	
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CSRegex_Destruct( ADDON_REF(IObject) thiz )
{
	addon_SRegex_data_ptr_t obj_data = (addon_SRegex_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;

	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CSRegex_AddRef( ADDON_REF(IObject) thiz )
{
	addon_SRegex_data_ptr_t obj_data = (addon_SRegex_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
	
	obj_data->ref_cnt++;
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CSRegex_Release( ADDON_REF(IObject) thiz )
{
	addon_SRegex_data_ptr_t obj_data = (addon_SRegex_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
	
	obj_data->ref_cnt -= 1;

	if ( 0 == obj_data->ref_cnt )
	{
		addon_obj_delete( (void *)thiz );
	}
	
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CSRegex_SetPattern( ADDON_REF(IObject) thiz, addon_regcond_ptr_t pcond, unsigned long ncond )
{
	addon_SRegex_data_ptr_t obj_data = (addon_SRegex_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
	
	if ( NULL == pcond || 0 == ncond )
		return ADDON_FAILED;
	
	obj_data->ncond = ncond;
	obj_data->pcond = pcond;	
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CSRegex_Match( ADDON_REF(IObject) thiz, unsigned short * str, unsigned long len,
													unsigned long nmatch, addon_regmatch_ptr_t pmatch )
{
	unsigned long		i;
	unsigned long		j;
	unsigned long		ret_val;
	unsigned long		pos;
	unsigned long		pos2;
	unsigned long		len2;
	addon_regmatch_t	tmp_match;
	
	addon_SRegex_data_ptr_t	obj_data = (addon_SRegex_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
	
	if ( NULL == str || 0 == len || NULL == pmatch || 0 == nmatch )
		return ADDON_FAILED;
	
	for ( pos = 0; pos < len; ++pos )
	{
		pos2 = pos;
		len2 = len - pos;
		
		for ( i = 0, j = 0; i < obj_data->ncond && j < nmatch; ++i, ++j )
		{
			tmp_match.offset_beg = 0;
			tmp_match.offset_end = 0;

			ret_val = __match_condition( &str[pos2], len2, &obj_data->pcond[i], &tmp_match );
			if ( 0 == ret_val )
			{
				// against the rules
				break;
			}

			pmatch[j].offset_beg = pos2 + tmp_match.offset_beg;
			pmatch[j].offset_end = pos2 + tmp_match.offset_end;

			pos2 += (tmp_match.offset_end - tmp_match.offset_beg);
			len2 -= (tmp_match.offset_end - tmp_match.offset_beg);
		}

		if ( j >= nmatch )
		{
			return ADDON_OK;
		}
	}

	return ADDON_FAILED;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
ADDON_EXPORT ADDON_REF(IObject) addon_create_sregex( void * reserved )
{
	//static const 
		void * __coclass_vtbl[6];// =
	int i=0;//{
		// IObject
__coclass_vtbl[i++] = 	(void *)__CSRegex_Construct;
__coclass_vtbl[i++] = 	(void *)__CSRegex_Destruct;
__coclass_vtbl[i++] = 	(void *)__CSRegex_AddRef;
__coclass_vtbl[i++] = 	(void *)__CSRegex_Release;

		// IAddonSetting
__coclass_vtbl[i++] = 	(void *)__CSRegex_SetPattern;
__coclass_vtbl[i++] = 	(void *)__CSRegex_Match;
	//};

// 	static const addon_coclass_desc_t __coclass_desc =
// 	{
// 		(unsigned char *)__coclass_vtbl,
// 		(unsigned long)sizeof( addon_SRegex_data_t )
// 	};
		addon_coclass_desc_t __coclass_desc;
		
		__coclass_desc.vtbl_size	= (unsigned long)sizeof(__coclass_vtbl);
		__coclass_desc.vtbl_funcs	= (unsigned char *)__coclass_vtbl;
		__coclass_desc.priv_size	= (unsigned long)sizeof(addon_SRegex_data_t);
		

	return ( ADDON_REF(IObject) )addon_obj_new( (addon_coclass_desc_ptr_t)&__coclass_desc, reserved );
}

#else	// #if (__ADDON_TARGET__ == __TARGET_SYMBIAN)

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
ADDON_EXPORT ADDON_REF(IObject) addon_create_sregex( void * reserved )
{
	ADDON_UNUSED( reserved );
	return NULL;
}

#endif	// #if (__ADDON_TARGET__ == __TARGET_SYMBIAN)
